char *arg1_name, *arg1, *arg2_name, *arg2, *decision = NULL;
struct acm_getdecision getdecision;
int xc_handle, rc;
+ uint32_t hooktype;
- if (!PyArg_ParseTuple(args, "ssss", &arg1_name,
- &arg1, &arg2_name, &arg2)) {
+ if (!PyArg_ParseTuple(args, "ssssi", &arg1_name,
+ &arg1, &arg2_name, &arg2, &hooktype)) {
return NULL;
}
(strcmp(arg2_name, "domid") && strcmp(arg2_name, "ssidref")))
return NULL;
- getdecision.hook = ACMHOOK_sharing;
+ getdecision.hook = hooktype;
if (!strcmp(arg1_name, "domid")) {
getdecision.get_decision_by1 = ACM_GETBY_domainid;
getdecision.id1.domainid = atoi(arg1);
binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
+#decision hooks known to the hypervisor
+ACMHOOK_sharing = 1
+ACMHOOK_authorization = 2
+
#other global variables
NULL_SSIDREF = 0
err("Invalid id or ssidref type, string or int required")
try:
- decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1])
+ decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1],
+ ACMHOOK_sharing)
except:
err("Cannot determine decision.")
err("Cannot determine decision (Invalid parameter).")
+def has_authorization(ssidref):
+ """ Check if the domain with the given ssidref has authorization to
+ run on this system. To have authoriztion dom0's STE types must
+ be a superset of that of the domain's given through its ssidref.
+ """
+ rc = True
+ dom0_ssidref = int(acm.getssid(0)['ssidref'])
+ decision = acm.getdecision('ssidref', str(dom0_ssidref),
+ 'ssidref', str(ssidref),
+ ACMHOOK_authorization)
+ if decision == "DENIED":
+ rc = False
+ return rc
+
+
def hv_chg_policy(bin_pol, del_array, chg_array):
"""
Change the binary policy in the hypervisor
# allocation of 1MB. We free up 2MB here to be on the safe side.
balloon.free(2*1024) # 2MB should be plenty
- ssidref = security.calc_dom_ssidref_from_info(self.info)
- if ssidref == 0 and security.on():
- raise VmError('VM is not properly labeled.')
+ ssidref = 0
+ if security.on():
+ ssidref = security.calc_dom_ssidref_from_info(self.info)
+ if ssidref == 0:
+ raise VmError('VM is not properly labeled.')
+ if security.has_authorization(ssidref) == False:
+ raise VmError("VM is not authorized to run.")
try:
self.domid = xc.domain_create(
.fail_grant_setup = NULL,
/* generic domain-requested decision hooks */
.sharing = NULL,
+ .authorization = NULL,
.is_default_policy = chwall_is_default_policy,
};
return ret;
}
-int
-acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
-{
- struct domain *subj = rcu_lock_domain_by_id(id);
- int ret;
-
- if (subj == NULL)
- {
- printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
- return ACM_NULL_POINTER_ERROR;
- }
-
- ret = acm_init_domain_ssid_new(subj, ssidref);
-
- rcu_unlock_domain(subj);
-
- return ret;
-}
-
-int acm_init_domain_ssid_new(struct domain *subj, ssidref_t ssidref)
+int acm_init_domain_ssid(struct domain *subj, ssidref_t ssidref)
{
struct acm_ssid_domain *ssid;
int ret1, ret2;
return ACM_INIT_SSID_ERROR;
}
- write_lock(&ssid_list_rwlock);
- list_add(&ssid->node, &ssid_list);
- write_unlock(&ssid_list_rwlock);
-
printkd("%s: assigned domain %x the ssidref=%x.\n",
__func__, subj->domain_id, ssid->ssidref);
return ACM_OK;
acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
ssid->secondary_ssid = NULL;
- write_lock(&ssid_list_rwlock);
- list_del(&ssid->node);
- write_unlock(&ssid_list_rwlock);
-
xfree(ssid);
printkd("%s: Freed individual domain ssid (domain=%02x).\n",
__func__, id);
ret = acm_sharing(ssidref1, ssidref2);
break;
+ case ACMHOOK_authorization:
+ ret = acm_authorization(ssidref1, ssidref2);
+ break;
+
default:
/* deny */
break;
/* local cache structures for STE policy */
struct ste_binary_policy ste_bin_pol;
-static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
+static inline int have_common_type (ssidref_t ref1, ssidref_t ref2)
+{
int i;
if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&
ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )
{
for( i = 0; i< ste_bin_pol.max_types; i++ )
- if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
- ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i])
+ if ( ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&
+ ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])
{
printkd("%s: common type #%02x.\n", __func__, i);
return 1;
return 0;
}
+static inline int is_superset(ssidref_t ref1, ssidref_t ref2)
+{
+ int i;
+
+ if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&
+ ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )
+ {
+ for( i = 0; i< ste_bin_pol.max_types; i++ )
+ if (!ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&
+ ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])
+ {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+
/* Helper function: return = (subj and obj share a common type) */
static int share_common_type(struct domain *subj, struct domain *obj)
{
{
/* check for ssidref in range for policy */
ssidref_t ste_ssidref;
+
traceprintk("%s.\n", __func__);
read_lock(&acm_bin_pol_rwlock);
return (hct ? ACM_ACCESS_PERMITTED : ACM_ACCESS_DENIED);
}
+static int
+ste_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
+{
+ int iss = is_superset(
+ GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
+ GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2));
+ return (iss ? ACM_ACCESS_PERMITTED : ACM_ACCESS_DENIED);
+}
+
static int
ste_is_default_policy(void)
{
.pre_grant_setup = ste_pre_grant_setup,
.fail_grant_setup = NULL,
.sharing = ste_sharing,
+ .authorization = ste_authorization,
.is_default_policy = ste_is_default_policy,
};
}
/* protos */
-int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
-int acm_init_domain_ssid_new(struct domain *, ssidref_t ssidref);
+int acm_init_domain_ssid(struct domain *, ssidref_t ssidref);
void acm_free_domain_ssid(struct acm_ssid_domain *ssid);
int acm_init_binary_policy(u32 policy_code);
int acm_set_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size);
int (*pre_grant_setup) (domid_t id);
void (*fail_grant_setup) (domid_t id);
/* generic domain-requested decision hooks (can be NULL) */
- int (*sharing) (ssidref_t ssidref1, ssidref_t ssidref2);
+ int (*sharing) (ssidref_t ssidref1,
+ ssidref_t ssidref2);
+ int (*authorization) (ssidref_t ssidref1,
+ ssidref_t ssidref2);
/* determine whether the default policy is installed */
int (*is_default_policy) (void);
};
{ return 0; }
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
{ return 0; }
+static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
+{ return 0; }
static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
{ return 0; }
static inline void acm_domain_destroy(struct domain *d)
#else
+static inline void acm_domain_ssid_onto_list(struct acm_ssid_domain *ssid)
+{
+ write_lock(&ssid_list_rwlock);
+ list_add(&ssid->node, &ssid_list);
+ write_unlock(&ssid_list_rwlock);
+}
+
+static inline void acm_domain_ssid_off_list(struct acm_ssid_domain *ssid)
+{
+ write_lock(&ssid_list_rwlock);
+ list_del(&ssid->node);
+ write_unlock(&ssid_list_rwlock);
+}
static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
{
if (acm_secondary_ops->domain_destroy != NULL)
acm_secondary_ops->domain_destroy(ssid, d);
/* free security ssid for the destroyed domain (also if null policy */
+ acm_domain_ssid_off_list(ssid);
acm_free_domain_ssid((struct acm_ssid_domain *)(ssid));
}
}
{
void *subject_ssid = current->domain->ssid;
domid_t domid = d->domain_id;
- int rc = 0;
+ int rc;
read_lock(&acm_bin_pol_rwlock);
/*
To be called when a domain is created; returns '0' if the
domain is allowed to be created, != '0' if not.
*/
+ rc = acm_init_domain_ssid(d, ssidref);
+ if (rc != ACM_OK)
+ goto error_out;
if ((acm_primary_ops->domain_create != NULL) &&
acm_primary_ops->domain_create(subject_ssid, ssidref, domid)) {
/* roll-back primary */
if (acm_primary_ops->domain_destroy != NULL)
acm_primary_ops->domain_destroy(d->ssid, d);
- acm_free_domain_ssid(d->ssid);
rc = ACM_ACCESS_DENIED;
}
- if (rc == 0) {
- rc = acm_init_domain_ssid_new(d, ssidref);
-
- if (rc != ACM_OK) {
- acm_domain_destroy(d);
- }
+ if ( rc == ACM_OK )
+ {
+ acm_domain_ssid_onto_list(d->ssid);
+ } else {
+ acm_free_domain_ssid(d->ssid);
}
+error_out:
read_unlock(&acm_bin_pol_rwlock);
return rc;
}
}
+static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
+{
+ if ((acm_primary_ops->authorization != NULL) &&
+ acm_primary_ops->authorization(ssidref1, ssidref2))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->authorization != NULL) &&
+ acm_secondary_ops->authorization(ssidref1, ssidref2)) {
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+
extern int acm_init(char *policy_start, unsigned long policy_len);
/* Return true iff buffer has an acm policy magic number. */
typedef uint32_t ssidref_t;
/* hooks that are known to domains */
-#define ACMHOOK_none 0
-#define ACMHOOK_sharing 1
+#define ACMHOOK_none 0
+#define ACMHOOK_sharing 1
+#define ACMHOOK_authorization 2
/* -------security policy relevant type definitions-------- */